package work.linruchang.util;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.lang.Console;
import cn.hutool.core.map.CaseInsensitiveMap;
import cn.hutool.core.stream.CollectorUtil;
import cn.hutool.core.text.csv.CsvReadConfig;
import cn.hutool.core.text.csv.CsvReader;
import cn.hutool.core.text.csv.CsvRow;
import cn.hutool.core.text.csv.CsvUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import lombok.Data;

import javax.sql.DataSource;
import java.io.InputStream;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;

/**
 * @author LinRuChang
 * @version 1.0
 * @date 2023/02/04
 * @since 1.8
 **/
public class EnhanceDbUtil {

    private static final String dbTypeNeedTypeLength = "system/dict/dbTypeNeedTypeLength.txt";
    private static Map<String, DbTypeNeedTypeLength> dbTypeNeedTypeLengthMap;

    @Data
    private static class DbTypeNeedTypeLength {

        /**
         * 数据列类型名
         */
        String columnType;

        /**
         * 当前列是否需要定义长度
         */
        Boolean needSizeFlag;

        /**
         * 当前列是否需要定义小数点长度
         */
        Boolean needDigitFlag;
    }

    static {
        InputStream resourceAsStream = EnhanceDbUtil.class.getClassLoader().getResourceAsStream(dbTypeNeedTypeLength);

        CsvReadConfig csvReadConfig = CsvReadConfig.defaultConfig();
        csvReadConfig.setContainsHeader(true);
        csvReadConfig.setTrimField(true);

        CsvReader csvReader = CsvUtil.getReader(IoUtil.getReader(resourceAsStream, CharsetUtil.UTF_8), csvReadConfig);


        dbTypeNeedTypeLengthMap = csvReader.stream().map(CsvRow::getFieldMap)
                .map(row -> BeanUtil.toBean(row, DbTypeNeedTypeLength.class))
                .collect(CollectorUtil.toMap(DbTypeNeedTypeLength::getColumnType, Function.identity(), (v1, v2) -> v2, CaseInsensitiveMap::new));
    }

    /**
     * 当前数据库字段类型是否需要类型长度
     *
     * @param dbColumnTypeName
     * @return
     */
    public static boolean isNeedDbColumnTypeLength(String dbColumnTypeName) {
        return Optional.ofNullable(dbTypeNeedTypeLengthMap.get(dbColumnTypeName))
                .map(DbTypeNeedTypeLength::getNeedSizeFlag)
                .orElse(false);
    }

    /**
     * 当前列是否需要定义小数点长度
     *
     * @param dbColumnTypeName
     * @return
     */
    public static boolean isNeedDbDigitTypeLength(String dbColumnTypeName) {
        return Optional.ofNullable(dbTypeNeedTypeLengthMap.get(dbColumnTypeName))
                .map(DbTypeNeedTypeLength::getNeedDigitFlag)
                .orElse(false);
    }

    /**
     * 构建DB列类型
     * demo：char 4 10 => char(4,10)
     *
     * @param dbColumnTypeName 列类型
     * @param length           列长度
     * @param decimalLength    列小数点长度
     * @return
     */
    public static String buildDbTypeDDL(String dbColumnTypeName, Integer length, Integer decimalLength) {

        String result = dbColumnTypeName;
        length = ObjUtil.defaultIfNull(length, 0);
        decimalLength = ObjUtil.defaultIfNull(decimalLength, 0);
        if (isNeedDbColumnTypeLength(dbColumnTypeName)) {

            List<Integer> numParams = CollUtil.newArrayList();
            numParams.add(length);

            if (isNeedDbDigitTypeLength(dbColumnTypeName)) {
                numParams.add(decimalLength);
            }

            result = StrUtil.format("{}({})", dbColumnTypeName, StrUtil.join(StrUtil.COMMA, numParams));
        }

        return result;
    }

    /**
     * 列定义
     * demo：name varchar 4 10 => name varchar(4)
     *
     * @param columnName       列名
     * @param dbColumnTypeName 列类型
     * @param length           列类型长度
     * @param decimalLength    列小数点长度
     * @return
     */
    public static String buildColumnDDL(String columnName, String dbColumnTypeName, Integer length, Integer decimalLength) {
        String dbTypeDDL = buildDbTypeDDL(dbColumnTypeName, length, decimalLength);
        return StrUtil.format("{} {}", columnName, dbTypeDDL);
    }

    /**
     * 测试数据库源是否可以连接成功
     * @param dataSource 数据源
     * @return
     */
    public static boolean testDbConnection(DataSource dataSource) {
        boolean result = false;
        if(dataSource != null) {
            try {
                dataSource.getConnection();
                result = true;
            }catch (Exception e) {
            }
        }
        return result;
    }


    public static void main(String[] args) {
        boolean aChar = EnhanceDbUtil.isNeedDbColumnTypeLength("char");
        Console.log(aChar);

        aChar = EnhanceDbUtil.isNeedDbColumnTypeLength("CHAR");
        Console.log(aChar);
    }

}
